package com.blog.aspect;

import com.blog.annotation.RequiredLog;
import com.blog.entity.Log;
import com.blog.entity.User;
import com.blog.mapper.LogMapper;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Date;

//@Order(1)//定义切面优先级，数字越小，优先级越高
//@Aspect
//@Component
public class OperLogAspect {
    private static Logger log= LoggerFactory.getLogger(OperLogAspect.class);
    @Pointcut("@annotation(com.blog.annotation.RequiredLog)")
    public void doLog(){}

    @Around(value = "@annotation(requiredLog)")
    public Object doLogAround(ProceedingJoinPoint joinPoint,RequiredLog requiredLog)throws  Throwable{
        log.info("OperLogAspect.doLogAround.before");
        Integer status=1;//ok
        String error="";
        Long time=0L;
        long t1=System.currentTimeMillis();
        try {
            Object result = joinPoint.proceed();
            long t2=System.currentTimeMillis();
            time=t2-t1;
            return result;
        }catch (Throwable e){
            long t3=System.currentTimeMillis();
            time=t3-t1;
            status=0;
            error=e.getMessage();
            throw e;
        }finally{
            saveUserLog(joinPoint,requiredLog,time,status,error);
        }
    }
    private void saveUserLog(ProceedingJoinPoint joinPoint,RequiredLog requiredLog,
                             Long time, Integer status, String error)
            throws NoSuchMethodException, JsonProcessingException {
        //1.获取用户行为日志
        //1.1获取用户ip,登陆用户
        //1.1.1 获取请求对象(在非Filter,Servlet，Controller对象中获取请求可以基于RequestContextHolder对象获取即可)
        ServletRequestAttributes requestAttributes=
                (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = requestAttributes.getRequest();
        //1.1.2获取ip地址
        String ip=request.getRemoteAddr();
        //1.1.3假如登录用户存储到了session，我可以从session获取用户信息
        String username="";
        User user= (User) request.getSession().getAttribute("user");
        if(user!=null){
            username=user.getUsername();
        }
        //1.2获取用户操作(切入点方法上RequiredLog注解内部operation的值)
        String operation=requiredLog.operation();
        //1.3用户执行操作时执行的什么方法(类全名+方法名)
        String className = joinPoint.getTarget().getClass().getName();
        String methodName = joinPoint.getSignature().getName();
        String method=className+"."+ methodName;
        //1.4执行方法时传递的参数是什么？(建议以json格式进行记录)
        String params=//基于jackson中的api将参数转换为json格式字符串
                new ObjectMapper()
                        .writeValueAsString(joinPoint.getArgs());
        //2.封装用户行为日志
        Log userLog=new Log();
        userLog.setIp(ip);
        userLog.setUsername(username);
        userLog.setCreatedTime(new Date());
        userLog.setOperation(operation);
        userLog.setMethod(method);
        userLog.setParams(params);
        userLog.setTime(time);
        userLog.setStatus(status);
        userLog.setError(error);
        //3.记录用户行为日志(文件、数据库表、MQ)
        logMapper.insert(userLog);
    }
    @Autowired
    private LogMapper logMapper;

}
